﻿//-----------------------------------------------------------------------
// <copyright file="MLCodeTemplate.cs" company="MAPILab Ltd">
//     Copyright (c) MAPILab Ltd.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace MAPILab.SharePoint.Explorer.CodeForm.CodeTemplates
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Reflection;
    using System.Text;
    using MAPILab.SharePoint.Explorer.Properties;
    using MAPILab.SharePoint.Explorer.Utilities;

    /// <summary>
    /// Base class code templates for C# and VB.NET languages
    /// </summary>
    public abstract class MLBaseCodeTemplate
    {      
        #region Fields

        /// <summary>
        /// Count parameters for method
        /// </summary>
        protected int methodsParamCounter=1;

        /// <summary>
        /// Dictionary with pairs: parameter name and parameter value
        /// </summary>
        protected Dictionary<string, object> parametersObject;

        /// <summary>
        /// List of parameters for main metod
        /// </summary>
        protected List<object> mainParams;

        /// <summary>
        /// Collection of references
        /// </summary>
        protected StringCollection references;

        #endregion

        #region Properties
        /// <summary>
        /// Get and set dictionary of parameters
        /// </summary>
        public Dictionary<string, object> ParametersObject
        {
            get { return parametersObject; }
            set { parametersObject = value; }
        }
        /// <summary>
        /// Get and set collection of references
        /// </summary>
        public StringCollection References
        {
            get { return references; }
            set { references = value; }
        }
        /// <summary>
        /// Get and set parameters for main metod
        /// </summary>
        public List<object> MainParameters
        {
            get { return mainParams; }
            set { mainParams = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Abstract metod for Generation Code Template
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <returns>string that contains code template</returns>
        public abstract string GenerateTemplate();

        /// <summary>
        /// Generate template for output
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <param name="template">string that contains code</param>
        protected virtual void GenerateOutput(StringBuilder template) { }

        /// <summary>
        /// Add Type References to Grid with all references
        /// </summary>
        /// <param name="paramType">parameter type</param>
        protected void AddTypeReferences(Type parameterType)
        {
            string refName = parameterType.Module.Name;
            string fqRefName = parameterType.Module.FullyQualifiedName;

            if (references == null)
                references = new StringCollection();

            //Add new referense to collection of references
            if (!Settings.Default.references.Contains(refName) && !references.Contains(fqRefName))
                references.Add(fqRefName);

            //Processing Base type
            if (parameterType.BaseType != null)
            {
                AddTypeReferences(parameterType.BaseType);
            }

            //Processing Generic types
            if (parameterType.IsGenericType)
            {
                foreach (Type genericType in parameterType.GetGenericArguments())
                    AddTypeReferences(genericType);
            }
        }

        /// <summary>
        /// Add parameters to Main method
        /// </summary>
        /// <param name="template">output template</param>
        protected void AddMainParameters(StringBuilder template)
        {
            bool firstParam = true;
            if (ParametersObject != null)
            {
                mainParams = new List<object>();
                foreach (KeyValuePair<string, object> kvp in ParametersObject)
                {
                    object paramValue = kvp.Value;

                    if (paramValue is MLMethodParameter)
                    {
                        MLMethodParameter methParam = paramValue as MLMethodParameter;
                        if (methParam.ObjectValue != null)
                        {
                            methParam.MainParamName = string.Format("mo_{0}", kvp.Key);

                            AddMainParameter(template, ref firstParam, methParam.MainParamName, methParam.ObjectValue);
                            AddMainParameter(template, ref firstParam, kvp.Key, methParam.MethodInfo);
                        }
                    }
                    else
                    {
                        if (paramValue != null)
                        {
                            AddMainParameter(template, ref firstParam, kvp.Key, paramValue);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Add current parameter to Main method
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="firstParam">is first parameter or not</param>
        /// <param name="paramName">Parameter name</param>
        /// <param name="paramValue">Parameter value</param>
        protected virtual void AddMainParameter(StringBuilder template, ref bool firstParam, string paramName, object paramValue) { }

        /// <summary>
        /// Add methods to code template
        /// </summary>
        /// <param name="template">output template</param>
        protected void GenerateMethodsCallTemplate(StringBuilder template)
        {
            if (ParametersObject != null)
            {
                foreach (KeyValuePair<string, object> kvp in ParametersObject)
                {
                    object paramValue = kvp.Value;
                    if (paramValue is MLMethodParameter)
                    {
                        MLMethodParameter methParam = paramValue as MLMethodParameter;
                        if (methParam.ObjectValue != null)
                        {
                            GenerateMethodCallTemplate(template, methParam);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Add current method
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        protected virtual void GenerateMethodCallTemplate(StringBuilder template, MLMethodParameter methParam) { }

        /// <summary>
        /// Add non public method
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        /// <param name="methodInfo">adding method</param>
        /// <param name="paramList">parameters list</param>
        /// <param name="nonVoidIndent">non void indent</param>
        protected virtual void AddNonPublicMethod(StringBuilder template, MLMethodParameter methParam, MethodInfo methodInfo, List<ParameterNameAndType> paramList, bool nonVoidIndent) { }

        /// <summary>
        /// Add public method
        /// It is overriden in MLCSharpCodeTemplate and MLVBNetCodeTemplate
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        /// <param name="methodInfo">adding method</param>
        /// <param name="paramList">parameters list</param>
        /// <param name="nonVoidIndent">non void indent</param>
        protected virtual void AddPublicMethod(StringBuilder template, MLMethodParameter methParam, MethodInfo methodInfo, List<ParameterNameAndType> paramList, bool nonVoidIndent) { }

        /// <summary>
        /// Adding method parameters on template and return parameter list
        /// </summary>
        /// <param name="template">output temlate</param>
        /// <param name="parameters">parameters of adding method</param>
        /// <returns>parameters list</returns>
        protected List<ParameterNameAndType> AddMethodParameters(StringBuilder template, ParameterInfo[] parameters)
        {
            List<ParameterNameAndType> paramList = new List<ParameterNameAndType>();
            //Adding parameters for method 
            foreach (ParameterInfo paramInfo in parameters)
            {
                ParameterNameAndType parameterNameAndType = new ParameterNameAndType();
                parameterNameAndType.Name = string.Format("value{0}", methodsParamCounter++);

                Type paramType = paramInfo.ParameterType;
                if (paramType.IsByRef)
                {
                    paramType = paramType.GetElementType();

                    if (paramInfo.IsOut)
                    {
                        parameterNameAndType.IsOutParameter = true;
                    }
                    else
                    {
                        parameterNameAndType.IsRefParameter = true;
                    }
                }

                parameterNameAndType.TypeName = MLUtils.GetTypeOutput(paramType);

                paramList.Add(parameterNameAndType);
            }


            return paramList;
        }

        /// <summary>
        /// Add parametrs for method
        /// </summary>
        /// <param name="template">code template</param>
        /// <param name="paramList">method parameter to add</param>
        /// <param name="nonVoidIndent">non void indent</param>
        /// <param name="IsInvoke">is invoke metod or not</param>
        protected virtual void GetParameters(StringBuilder template, List<ParameterNameAndType> paramList, bool nonVoidIndent, bool IsInvoke) { }

        #endregion
    }
}
